//
//  DDropTimeMarkLayer.swift
//  Drop
//
//  Created by hushaohua on 2018/9/23.
//  Copyright © 2018年 init. All rights reserved.
//

import UIKit

struct DDropTimeMarkLine {
    var lineBegin:CGPoint = .zero;
    var lineEnd:CGPoint = .zero;
    var lineWidth:CGFloat = 1;
    
    init() {
        
    }
}

class DDropTimeMarkLayer: CALayer{
    
    var beginDateTime:Date;
    var endDateTime:Date;
    func setDates(_ begin:Date, end:Date) {
        self.beginDateTime = begin;
        self.endDateTime = end;
        self.getMarkLayers();
    }
    
    override init() {
        self.beginDateTime = Date();
        self.endDateTime = Date();
        super.init();
    }
    convenience init(begin:Date, end:Date){
        self.init();
        self.beginDateTime = begin;
        self.endDateTime = end;
        self.getMarkLayers();
    }
    
    var marks:[DDropTimeMarkLine] = [DDropTimeMarkLine]();
    var textLayers:[CATextLayer] = [CATextLayer]();
    func getTextLayer(at index:Int) -> CATextLayer{
        if (self.textLayers.count > index){
            return self.textLayers[index];
        }else{
            let layer:CATextLayer = self.textLayer();
            self.textLayers.append(layer);
            self.addSublayer(layer);
            return layer;
        }
    }
    func textLayer() -> CATextLayer{
        let layer:CATextLayer = CATextLayer();
        layer.frame = CGRect(x: 0, y: 0, width: 28, height: self.bounds.size.height / 2);
        layer.contentsScale = UIScreen.main.scale;
        layer.foregroundColor = UIColor.gray.cgColor;
        let fontRef = CGFont.init(UIFont.familyNames.first! as CFString);
        layer.font = fontRef;
        layer.fontSize = 8;
        return layer;
    }
    func getMarkLayers(){
        let minutes = self.endDateTime.timeIntervalSince(self.beginDateTime) / 60;
        let miniInterval:DrawMarkInterval = self.bestInterval(minutes, .tenMinutes);
        let calendar = Calendar.current;
        var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: self.beginDateTime);
        
        var date:Date? = nil;
        let factor = components.minute! / miniInterval.rawValue + 1;
        components.minute = factor * miniInterval.rawValue;
        if (components.minute! % 60 == 0){
            components.minute = 0
            date = self.nextHourBegin(self.beginDateTime);
        }else{
            date = calendar.date(from: components);
        }
        
        let depth = 1 / UIScreen.main.scale;
        let totalInterval = self.endDateTime.timeIntervalSince(self.beginDateTime);
        var interval = date?.timeIntervalSince(self.beginDateTime);
        var index:Int = 0;
        while (self.endDateTime.timeIntervalSince(date!) > 0){
            components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date!);
            var mark:DDropTimeMarkLine = DDropTimeMarkLine();
            let offsetX:CGFloat = CGFloat(interval! / totalInterval) * self.bounds.size.width;
            if components.minute == 0 {
                mark.lineBegin = CGPoint(x: offsetX, y: 6);
                mark.lineEnd = CGPoint(x: offsetX, y: self.bounds.size.height - 6);
                mark.lineWidth = 1;
                let layer = self.getTextLayer(at: index);
                if (components.hour! != 0 && components.hour! != 24){
                    layer.string = "\(components.hour!)" as NSString;
                }else{
                    layer.string = "\(components.month!)-\(components.day!)" as NSString;
                }
                
                layer.frame = CGRect(x:offsetX + 3, y:0, width:18, height:self.bounds.size.height - 0);
                index = index + 1;
            } else if components.minute == 30 {
                mark.lineWidth = depth;
                mark.lineBegin = CGPoint(x: offsetX, y: 8);
                mark.lineEnd = CGPoint(x: offsetX, y: self.bounds.size.height - 8);
            } else {
                mark.lineWidth = depth;
                mark.lineBegin = CGPoint(x: offsetX, y: 10);
                mark.lineEnd = CGPoint(x: offsetX, y: self.bounds.size.height - 10);
            }
            self.marks.append(mark);
            interval = interval! + TimeInterval(miniInterval.rawValue) * 60;
            date = Date(timeInterval: interval!, since: self.beginDateTime);
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    enum DrawMarkInterval:Int {
        case tenMinutes = 10, quarater = 15, halfHour = 30, hour = 60, dHour = 120, qHour = 240, hHour = 360
        func next() -> DrawMarkInterval{
            switch self {
            case .tenMinutes:
                return .quarater;
            case .quarater:
                return .halfHour;
            case .halfHour:
                return .hour;
            case .hour:
                return .dHour;
            case .dHour:
                return .qHour;
            case .qHour:
                return .hHour;
            default:
                return .hHour;
            }
        }
    }
    
    func bestInterval(_ minutes:TimeInterval, _ interval:DrawMarkInterval) -> DrawMarkInterval{
        let width = self.bounds.size.width / CGFloat(minutes / Double(interval.rawValue));
        if (width >= 30){
            return interval;
        }else{
            return self.bestInterval(minutes, interval.next());
        }
    }
    
    func nextHourBegin(_ date:Date) -> Date{
        let calendar = Calendar.current;
        var comp = DateComponents();
        comp.hour = 1;
        let nextHour = calendar.date(byAdding: comp, to: date);
        comp = calendar.dateComponents([.year, .month, .day, .hour], from: nextHour!);
        let date = calendar.date(from: comp);
        return date!;
    }
    
    override func draw(in ctx: CGContext) {
        super.draw(in: ctx);
        
        ctx.setStrokeColor(UIColor.lightGray.cgColor);
        for mark in self.marks {
            ctx.setLineWidth(mark.lineWidth);
            ctx.move(to: mark.lineBegin);
            ctx.addLine(to: mark.lineEnd);
            ctx.closePath();
            ctx.strokePath();
        }
        
        ctx.setLineWidth(1);
        ctx.move(to: CGPoint(x:0, y:self.bounds.size.height / 2));
        ctx.addLine(to: CGPoint(x:self.bounds.size.width, y:self.bounds.size.height / 2));
        ctx.strokePath();
    }
}
